<?php

namespace app\factory\wxPay;

use think\facade\Config;
use think\facade\Request;
use WeChatPay\Builder;
use WeChatPay\Crypto\AesGcm;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;

/**
 * 支付
 * Class Pay
 * @package app\factory
 *
 */
class WxV3Pay
{
    public function payNotifyV3()
    {
        $inWechatpaySignature = Request::header('Wechatpay-Signature');// 请根据实际情况获取
        $inWechatpayTimestamp = Request::header('Wechatpay-Timestamp');// 请根据实际情况获取
//        $inWechatpaySerial = Request::header('Wechatpay-Serial');// 请根据实际情况获取
        $inWechatpayNonce = Request::header('Wechatpay-Nonce');// 请根据实际情况获取
        $inBody = file_get_contents('php://input');// 请根据实际情况获取，例如: file_get_contents('php://input');
//        file_put_contents("wx_josn.text", $inBody . "||" . $inWechatpaySignature . "||" . $inWechatpayTimestamp . "||" . $inWechatpayNonce);
        $apiv3Key = Config::get('system.wx_pay.key3');;// 在商户平台上设置的APIv3密钥
        // 根据通知的平台证书序列号，查询本地平台证书文件，
        // 假定为 `/path/to/wechatpay/inWechatpaySerial.pem`
        $platformCertificateFilePath = Config::get('system.wx_pay.verify_cert_path');
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

        // 检查通知时间偏移量，允许5分钟之内的偏移
        $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
        $verifiedStatus = Rsa::verify(
        // 构造验签名串
            Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
            $inWechatpaySignature,
            $platformPublicKeyInstance
        );
        if ($timeOffsetStatus && $verifiedStatus) {
            // 转换通知的JSON文本消息为PHP Array数组
            $inBodyArray = json_decode($inBody, true);
            $resource = $inBodyArray['resource'];

//            file_put_contents("wx_out_pay_ciphertext.txt", $resource['ciphertext']);
//            file_put_contents("wx_out_pay_nonce.txt", $resource['nonce']);
//            file_put_contents("wx_out_pay_associated_data.txt", $resource['associated_data']);
//            file_put_contents("wx_out_pay_associated_apiv3Key.txt", $apiv3Key);

            // 加密文本消息解密
            $inBodyResource = AesGcm::decrypt($resource['ciphertext'], $apiv3Key, $resource['nonce'], $resource['associated_data']);
            // 把解密后的文本转换为PHP Array数组
            $inBodyResourceArray = (array)json_decode($inBodyResource, true);
            file_put_contents("wxpay/success/" . $inBodyResourceArray['out_trade_no'] . "_v3.txt", $inBodyResource);
            $pay_sn = $inBodyResourceArray['out_trade_no']; //我的支付编号
            $price = $inBodyResourceArray['amount']['total']; //支付金额
            $res = PayHandle::pay_handle($pay_sn, $price, 'weixin');//支付处理
            if ($res['code']) {
                echo "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";//返回微信通知
            }
        }
    }

    /**
     * 查询订单支付情况
     * @param string $pay_sn
     * @return array
     */
    public function payQueryV3($pay_sn = '')
    {
        // 商户号
        $merchantId = Config::get('system.wx_pay.mch_id');
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = Config::get('system.wx_pay.key_path');
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        // 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = Config::get('system.wx_pay.serial');
        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        $platformCertificateFilePath = Config::get('system.wx_pay.verify_cert_path');
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
//        $platformPublicKeyInstance = PemUtil::loadCertificate($platformCertificateFilePath);
        // 从「微信支付平台证书」中获取「证书序列号」
//        $platformCertificateSerial = "1FD1D321DBD266FA742484BCEA3A8A07A5783BB7";
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);

        // 构造一个 APIv3 客户端实例
        $client = Builder::factory([
            'mchid' => $merchantId,
            'serial' => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);
        try {
            $resp = $client
                ->chain('v3/pay/transactions/out-trade-no/' . $pay_sn . "?mchid=" . $merchantId)
                ->get();
            $body = $resp->getBody();
            $data = json_decode($body, true);
            if (isset($data['trade_state'])) {
                if ($data['trade_state'] == "SUCCESS") {
                    $pay_sn = $data['out_trade_no']; //我的支付编号
                    $price = $data['amount']['total']; //支付金额
                    PayHandle::pay_handle($pay_sn, $price, 'weixin');//支付处理
                    return [
                        'code' => 1,
                        'data' => $pay_sn,
                        'msg' => '操作'
                    ];
                }
            }
            $data_out = [
                'code' => 1,
                'data' => 0,
                'msg' => '操作'
            ];
            return $data_out;
        } catch (\Exception $e) {
            // 进行错误处理
            $data_out = [
                'code' => 0,
                'msg' => '获取失败'
            ];
            return $data_out;
        }
    }

    public function getQRcode($pay_sn, $total, $body = "")
    {
        $appid = Config::get('system.wx_pay.app_id');
        // 商户号
        $merchantId = Config::get('system.wx_pay.mch_id');
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = Config::get('system.wx_pay.key_path3');
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        // 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = Config::get('system.wx_pay.serial');
        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        $platformCertificateFilePath = Config::get('system.wx_pay.verify_cert_path3');
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
//        $platformPublicKeyInstance = PemUtil::loadCertificate($platformCertificateFilePath);
        // 从「微信支付平台证书」中获取「证书序列号」
//        $platformCertificateSerial = "1FD1D321DBD266FA742484BCEA3A8A07A5783BB7";
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);

        // 构造一个 APIv3 客户端实例
        $client = Builder::factory([
            'mchid' => $merchantId,
            'serial' => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);
        try {
            $resp = $client
                ->chain('v3/pay/transactions/native')
                ->post(['json' => [
                    'mchid' => $merchantId,
                    'out_trade_no' => $pay_sn,
                    'appid' => $appid,
                    'description' => $body,
                    'notify_url' => 'https://sever.digi-legend.com/app_index/notify/payNotifyV3',
                    'amount' => [
                        'total' => $total,
                        'currency' => 'CNY'
                    ],
                ]]);
            $body = $resp->getBody();
            $data = json_decode($body, true);
            $data_out = [
                'code' => 1,
                'data' => $data['code_url'],
                'msg' => '获取成功'
            ];
            return $data_out;
        } catch (\Exception $e) {
            $data_out = [
                'code' => 0,
                'msg' => '获取失败'
            ];
            return $data_out;
            // 进行错误处理
        }

    }

    /**
     * 支付用户提现
     * @param $deposit_sn
     * @param $total
     * @param string $openid
     * @param string $body
     * @return array|mixed
     */
    public function payUserDeposit($deposit_sn, $total, $openid = '', $body = "")
    {
        $appid = Config::get('system.wx_pay.app_id');
        // 商户号
        $merchantId = Config::get('system.wx_pay.mch_id');
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = Config::get('system.wx_pay.key_path3');
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        // 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = Config::get('system.wx_pay.serial');
        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        $platformCertificateFilePath = Config::get('system.wx_pay.verify_cert_path3');
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
//        $platformPublicKeyInstance = PemUtil::loadCertificate($platformCertificateFilePath);
        // 从「微信支付平台证书」中获取「证书序列号」
//        $platformCertificateSerial = "1FD1D321DBD266FA742484BCEA3A8A07A5783BB7";
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
        // 构造一个 APIv3 客户端实例
        $client = Builder::factory([
            'mchid' => $merchantId,
            'serial' => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);
        try {
            $json = [
                'mchid' => $merchantId,
                'appid' => $appid,
                'out_batch_no' => $deposit_sn,
                'batch_name' => $body,
                'batch_remark' => $body,
                'total_amount' => $total,
                'total_num' => 1,
                'transfer_detail_list' => [
                    [
                        "out_detail_no" => $deposit_sn . "1",
                        "transfer_amount" => $total,
                        "transfer_remark" => $body,
                        "openid" => $openid
                    ]
                ],
            ];
            $resp = $client
                ->chain('v3/transfer/batches')
                ->post(['json' => $json]);
            $body = $resp->getBody();
            $data = json_decode($body, true);
            if (isset($data['out_batch_no'])) {
                return [
                    'code' => 1,
                    'msg' => '提现成功'
                ];
            }
            return [
                'code' => 0,
                'msg' => '提现失败'
            ];
        } catch (\Exception $e) {
            return [
                'code' => 0,
                'msg' => '提现失败'
            ];
            // 进行错误处理
        }
    }

    //查询提现订单到账情况
    public function queryUserDeposit($deposit_sn = '')
    {
        // 商户号
        $merchantId = Config::get('system.wx_pay.mch_id');
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = Config::get('system.wx_pay.key_path3');
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        // 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = Config::get('system.wx_pay.serial');
        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        $platformCertificateFilePath = Config::get('system.wx_pay.verify_cert_path3');
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
//        $platformPublicKeyInstance = PemUtil::loadCertificate($platformCertificateFilePath);
        // 从「微信支付平台证书」中获取「证书序列号」
//        $platformCertificateSerial = "1FD1D321DBD266FA742484BCEA3A8A07A5783BB7";
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
        // 构造一个 APIv3 客户端实例
        $client = Builder::factory([
            'mchid' => $merchantId,
            'serial' => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);
        try {
            $resp = $client
                ->chain('v3/transfer/batches/out-batch-no/' . $deposit_sn . "/details/out-detail-no/" . $deposit_sn . "1")
                ->get();
            $body = $resp->getBody();
            $data = json_decode($body, true);
            if (isset($data['out_batch_no'])) {
                if ($data['detail_status'] == "SUCCESS") {
                    return [
                        'code' => 1,
                        'msg' => '到账成功'
                    ];
                }
            }
            return [
                'code' => 0,
                'msg' => '到账失败'
            ];
        } catch (\Exception $e) {
//            echo $e->getMessage(), PHP_EOL;
//            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
//                $r = $e->getResponse();
//                echo $r->getStatusCode() . ' ' . $r->getReasonPhrase(), PHP_EOL;
//                echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
//            }
//            echo $e->getTraceAsString(), PHP_EOL;
            return [
                'code' => 0,
                'msg' => '提现失败'
            ];
            // 进行错误处理
        }
    }
}